package com.gr.jron.webapp.action;


import com.gr.jron.Constants;
import com.gr.jron.model.*;
import com.gr.jron.service.UserExistsException;
import com.gr.jron.util.JronUser.UserSex;
import com.gr.jron.util.JronUser.UserGroup;
import com.gr.jron.util.ServletTools;
import com.gr.jron.util.StringUtil;
import com.gr.jron.webapp.util.RequestUtil;
import net.sf.json.JSONObject;
import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.apache.struts2.ServletActionContext;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Action to allow new users to sign up.
 */
public class SignupAction extends BaseAction {
    private static final long serialVersionUID = 6558317334878272308L;
    private User user;
    private String cancel;
    private String userType;
    private String json;
    private UgGovermentInfo govermentInfo = new UgGovermentInfo();
    private UgTeamInfo teamInfo = new UgTeamInfo();
    private UgPersonInfo personInfo = new UgPersonInfo();
    private UgCompanyInfo companyInfo = new UgCompanyInfo();
    private String sex;

    public void setJson(String json) {
        this.json = json;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public void setCancel(String cancel) {
        this.cancel = cancel;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public String getUserType() {
        return userType;
    }

    public void setUserType(String userType) {
        this.userType = userType;
    }

    public UgGovermentInfo getGovermentInfo() {
        return govermentInfo;
    }

    public void setGovermentInfo(UgGovermentInfo govermentInfo) {
        this.govermentInfo = govermentInfo;
    }

    public UgTeamInfo getTeamInfo() {
        return teamInfo;
    }

    public void setTeamInfo(UgTeamInfo teamInfo) {
        this.teamInfo = teamInfo;
    }

    public UgPersonInfo getPersonInfo() {
        return personInfo;
    }

    public void setPersonInfo(UgPersonInfo personInfo) {
        this.personInfo = personInfo;
    }

    public UgCompanyInfo getCompanyInfo() {
        return companyInfo;
    }

    public void setCompanyInfo(UgCompanyInfo companyInfo) {
        this.companyInfo = companyInfo;
    }

    /**
     * Return an instance of the user - to display when validation errors occur
     *
     * @return a populated user
     */
    public User getUser() {
        return user;
    }

    /**
     * When method=GET, "input" is returned. Otherwise, "success" is returned.
     *
     * @return cancel, input or success
     */
    public String execute() {
        if (cancel != null) {
            return CANCEL;
        }
        if (ServletActionContext.getRequest().getMethod().equals("GET")) {
            return INPUT;
        }
        return SUCCESS;
    }

    /**
     * Returns "input"
     *
     * @return "input" by default
     */
    public String doDefault() {
        return INPUT;
    }

    public void unamechk() throws Exception {
        JSONObject jsonObject = JSONObject.fromObject(json);
        String uname = (String) jsonObject.get("username");
        user = userManager.getUserByName(uname);
        if (user != null)
            ServletTools.jsonMsgResponse(getText("msg.title.fail"), getText("errors.exist.username", new String[]{uname}), getResponse(), false);
        else
            ServletTools.jsonMsgResponse(getText("msg.title.success"), getText("username.available", new String[]{uname}), getResponse(), true);
    }

    public void emailchk() throws Exception {
        JSONObject jsonObj = JSONObject.fromObject(json);
        String email = (String) jsonObj.get("email");
        user = userManager.getUserByEmail(email);
        if (user != null)
            ServletTools.jsonMsgResponse(getText("msg.title.fail"), getText("errors.exist.email", new String[]{email}), getResponse(), false);
        else
            ServletTools.jsonMsgResponse(getText("msg.title.success"), getText("email.available", new String[]{email}), getResponse(), true);
    }

    /**
     * Save the user, encrypting their passwords if necessary
     *
     * @return success when good things happen
     * @throws Exception when bad things happen
     */
    public String save() throws Exception {

        switch (Integer.parseInt(userType)) {
            case 0:
                user.setUserGroup(UserGroup.PERSON);
                break;
            case 1:
                user.setUserGroup(UserGroup.COMPANY);
                break;
            case 2:
                user.setUserGroup(UserGroup.TEAM);
                break;
            case 3:
                user.setUserGroup(UserGroup.GOVERMENT);
                break;
        }
        log.debug("The " + user.getUsername() + " user type is: " + userType + " and after switch is: "
                + user.getUserGroup() + "(" + user.getUserGroup().ordinal() + ")");

        if (sex != null) {
            switch (Integer.parseInt(sex)) {
                case 0:
                    user.setSex(UserSex.MALE);
                    break;
                case 1:
                    user.setSex(UserSex.FEMALE);
                    break;
            }
        }
        log.debug("The " + user.getUsername() + " sex is: " + sex + " and after switch is: "
                + user.getSex() + "(" + user.getSex().ordinal() + ")");

        Boolean encrypt = (Boolean) getConfiguration().get(Constants.ENCRYPT_PASSWORD);
        if (encrypt != null && encrypt) {
            String algorithm = (String) getConfiguration().get(Constants.ENC_ALGORITHM);
            if (algorithm == null) { // should only happen for test case
                if (log.isDebugEnabled()) log.debug("assuming testcase, setting algorithm to 'SHA'");
                algorithm = "SHA";
            }
            user.setPassword(StringUtil.encodePassword(user.getPassword(), algorithm));
        }

        user.setEnabled(true);
        user.setRegDate(new Date());
        user.setIp(ServletTools.getRealIp(getRequest()));
        // Set the default user role on this new user
        user.addRole(roleManager.getRole(Constants.NORPVT_ROLE));

        try {
            if (user.getUserGroup().equals(UserGroup.COMPANY))
                user = userManager.saveUser(user, companyInfo);
            if (user.getUserGroup().equals(UserGroup.GOVERMENT))
                user = userManager.saveUser(user, govermentInfo);
            if (user.getUserGroup().equals(UserGroup.PERSON))
                user = userManager.saveUser(user, personInfo);
            if (user.getUserGroup().equals(UserGroup.TEAM))
                user = userManager.saveUser(user, teamInfo);
        } catch (AccessDeniedException ade) {
            // thrown by UserSecurityAdvice configured in aop:advisor userManagerSecurity
            log.warn(ade.getMessage());
            getResponse().sendError(HttpServletResponse.SC_FORBIDDEN);
            return null;
        } catch (UserExistsException e) {
            log.warn(e.getMessage());
            List<String> args = new ArrayList<String>();
            args.add(user.getUsername());
            args.add(user.getEmail());
            addActionError(getText("errors.existing.user", args));

            // redisplay the unencrypted passwords
            user.setPassword(user.getConfirmPassword());
            return INPUT;
        }
        saveMessage(getText("user.registered"));
        getSession().setAttribute(Constants.REGISTERED, Boolean.TRUE);

        // log user in automatically
        UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
                user.getUsername(), user.getConfirmPassword(), user.getAuthorities());
        auth.setDetails(user);
        SecurityContextHolder.getContext().setAuthentication(auth);

        // Send an account information e-mail
        mailMessage.setSubject(getText("signup.email.subject"));
        sendUserMessage(user, getText("signup.email.message"), RequestUtil.getAppURL(getRequest()));

        return SUCCESS;
    }
}
